#include "ForBuilder.h"

#include "ScriptCompiler/ScriptFileContext.h"
#include "ScriptCompiler/AST/ForNode.h"
#include "ScriptCompiler/AST/ExpressionSentence.h"
#include "ScriptCompiler/ASTBuilder/SentenceBlockBuilder.h"
#include "ScriptCompiler/ASTBuilder/SentenceBuilder.h"
#include "ScriptCompiler/ASTBuilder/ExpressionBuilder.h"

CForBuilder::CForBuilder(std::shared_ptr<CScriptFileContext> InContext)
{
    Context = InContext;
    Result = std::make_shared<CForNode>(InContext);
}

bool CForBuilder::ReadCurentToken()
{
    //read for
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::For)
        {
            Context->RaiseError(10046,Token, U"Expect 'for' here");
            return false;
        }
        Result->For = Token;
        Context->CurrentTokenIndex++;
    }

    //read '('
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::LeftParentheses)
        {
            Context->RaiseError(10047,Token, U"Expect '(' here");
            return false;
        }
        //Result->LeftParentheses = Token;
        Context->CurrentTokenIndex++;
    }

    //find ')'
    auto RightParenthesesIndex = FindPairedParentheses(Context);
    if(!RightParenthesesIndex.HasValue())
    {
        Context->RaiseError(10048,Context->GetCurrentToken(), U"Expect ')' at end of for-statement step");
        return false;
    }

    //read init
    {
        //find semicolon
        auto SemiColonIndex = FindNextToken(EScriptTokenType::Semicolon,Context);
        if(!SemiColonIndex.HasValue())
        {
            Context->RaiseError(10049,Context->GetCurrentToken(), U"Expect ';' for for-statement init");
            return false;
        }

        //check if init is empty
        if (SemiColonIndex.GetValue() != Context->CurrentTokenIndex)
        {
            auto SentenceBuilder = std::make_shared<CSentenceBuilder>(Context);
            if (!SentenceBuilder->ReadCurentToken())
            {
                return false;
            }

            Result->Init = SentenceBuilder->Result;
        }
        else
        {
            //this is a empty init
            Result->Init = nullptr;
        }

    }

    //read condition
    {
        //find semicolon
        auto SemiColonIndex = FindNextToken(EScriptTokenType::Semicolon,Context);
        if(!SemiColonIndex.HasValue())
        {
            Context->RaiseError(10050,Context->GetCurrentToken(), U"Expect ';' for for-statement condiion");
            return false;
        }

        //check if condition is empty
        if (SemiColonIndex.GetValue() == Context->CurrentTokenIndex)
        {
            //this is a empty condition
            Result->Condition = nullptr;
        }
        else
        {
            auto ExpressionBuilder = std::make_shared<CExpressionBuilder>(Context,SemiColonIndex.GetValue());
            if (!ExpressionBuilder->ReadCurentToken())
            {
                return false;
            }
            Result->Condition = ExpressionBuilder->Result; 
        }

        //skip ';'
        assert(SemiColonIndex.GetValue() == Context->CurrentTokenIndex);
        Context->CurrentTokenIndex++;
    }

    //read step
    {
        //check if step is empty
        if (RightParenthesesIndex.GetValue() == Context->CurrentTokenIndex)
        {
            //this is a empty step
            Result->Step = nullptr;

            //skip ')'
            assert(RightParenthesesIndex.GetValue() == Context->CurrentTokenIndex);
            Context->CurrentTokenIndex++;
        }
        else
        {
            auto SentenceBuilder = std::make_shared<CSentenceBuilder>(
                Context
                ,RightParenthesesIndex.GetValue());

            if (!SentenceBuilder->ReadCurentToken())
            {
                return false;
            }
            Result->Step =  SentenceBuilder->Result;
        }
    }

    //read ')'
    // {
    //     auto Token = Context->GetCurrentToken();
    //     if (Token->Type != EScriptTokenType::RightParentheses)
    //     {
    //         Context->RaiseError(10051,Token, U"Expect ')' here");
    //         return false;
    //     }
    //     Context->CurrentTokenIndex++;
    // }

    //read loop body
    //check is next token is '{'
    auto Token= Context->GetCurrentToken();
    if(Token->Type==EScriptTokenType::LeftBrace)
    {
        Context->CurrentTokenIndex++;
        //this is a block
        auto RightBraceTokenIndex= FindPairedBrace(Context);

        if(!RightBraceTokenIndex)
        {
            //raise error 
            Context->RaiseError(10150,Token,U"cant find paired '}'");
        }

        auto ExpressionBuilder = std::make_shared<CSentenceBlockBuilder>(
            Context,RightBraceTokenIndex.GetValue());
        if (!ExpressionBuilder->ReadCurentToken())
        {
            return false;
        }
        Result->Body = ExpressionBuilder->Result;

        //skip '}'
        assert(Context->GetCurrentToken()->Type==EScriptTokenType::RightBrace);
        Context->CurrentTokenIndex++;

        return true;
    }
    else
    {
        //there is only a single sencence as loop body without a paire '{}'
        //dont know how to find the end of sentence
        //but fortunately, write loop body without '{}' is a bad habit,
        //so disallow such grammer
        Context->RaiseError(10151,Token,U"cant find '{', do not allow write loop body without '{}'");
        return false;
    }

    return true;

}
